home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-11-24 | 54.2 KB | 2,444 lines |
- Newsgroups: comp.sources.misc
- From: jfh@rpp386.Cactus.ORG (John F Haugh II)
- Subject: v26i055: shadow - Shadow Password Suite, Part02/11
- Message-ID: <1991Nov24.184939.20009@sparky.imd.sterling.com>
- X-Md4-Signature: 6188fc99729d72bc4b581316b96e90f5
- Date: Sun, 24 Nov 1991 18:49:39 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: jfh@rpp386.Cactus.ORG (John F Haugh II)
- Posting-number: Volume 26, Issue 55
- Archive-name: shadow/part02
- Environment: UNIX
- Supersedes: shadow-2: Volume 06, Issue 22-24
-
- #! /bin/sh
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: groupadd.c passwd.c usermod.c
- # Wrapped by kent@sparky on Sun Nov 24 11:03:41 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 2 (of 11)."'
- if test -f 'groupadd.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'groupadd.c'\"
- else
- echo shar: Extracting \"'groupadd.c'\" \(7395 characters\)
- sed "s/^X//" >'groupadd.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1991, John F. Haugh II
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X */
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)groupadd.c 3.3 08:43:44 9/12/91";
- X#endif
- X
- X#include <sys/types.h>
- X#include <stdio.h>
- X#include <grp.h>
- X#include <ctype.h>
- X#include <fcntl.h>
- X
- X#ifdef BSD
- X#include <strings.h>
- X#else
- X#include <string.h>
- X#endif
- X
- X#include "config.h"
- X#include "shadow.h"
- X
- X#ifdef USE_SYSLOG
- X#include <syslog.h>
- X#endif
- X
- Xchar group_name[BUFSIZ];
- Xint group_id;
- X
- Xchar *Prog;
- X
- Xint oflg; /* permit non-unique group ID to be specified with -g */
- Xint gflg; /* ID value for the new group */
- X
- X#ifdef NDBM
- Xextern int gr_dbm_mode;
- Xextern int sg_dbm_mode;
- X#endif
- Xextern char *malloc();
- X
- Xextern struct group *getgrnam();
- Xextern struct group *gr_next();
- Xextern int gr_lock();
- Xextern int gr_unlock();
- Xextern int gr_rewind();
- Xextern int gr_open();
- X
- X#ifdef SHADOWGRP
- Xextern int sgr_lock();
- Xextern int sgr_unlock();
- Xextern int sgr_open();
- X#endif
- X
- X/*
- X * usage - display usage message and exit
- X */
- X
- Xusage ()
- X{
- X fprintf (stderr, "usage: groupadd [-g gid [-o]] group\n");
- X exit (2);
- X}
- X
- X/*
- X * new_grent - initialize the values in a group file entry
- X *
- X * new_grent() takes all of the values that have been entered and
- X * fills in a (struct group) with them.
- X */
- X
- Xvoid
- Xnew_grent (grent)
- Xstruct group *grent;
- X{
- X static char *empty_list = 0;
- X
- X memset (grent, 0, sizeof *grent);
- X grent->gr_name = group_name;
- X grent->gr_passwd = "*";
- X grent->gr_gid = group_id;
- X grent->gr_mem = &empty_list;
- X}
- X
- X#ifdef SHADOWGRP
- X/*
- X * new_sgent - initialize the values in a shadow group file entry
- X *
- X * new_sgent() takes all of the values that have been entered and
- X * fills in a (struct sgrp) with them.
- X */
- X
- Xvoid
- Xnew_sgent (sgent)
- Xstruct sgrp *sgent;
- X{
- X static char *empty_list = 0;
- X
- X memset (sgent, 0, sizeof *sgent);
- X sgent->sg_name = group_name;
- X sgent->sg_passwd = "!";
- X sgent->sg_adm = &empty_list;
- X sgent->sg_mem = &empty_list;
- X}
- X#endif /* SHADOWGRP */
- X
- X/*
- X * grp_update - add new group file entries
- X *
- X * grp_update() writes the new records to the group files.
- X */
- X
- Xvoid
- Xgrp_update ()
- X{
- X struct group grp;
- X#ifdef SHADOWGRP
- X struct sgrp sgrp;
- X#endif /* SHADOWGRP */
- X
- X /*
- X * Create the initial entries for this new group.
- X */
- X
- X new_grent (&grp);
- X#ifdef SHADOWGRP
- X new_sgent (&sgrp);
- X#endif /* SHADOWGRP */
- X
- X /*
- X * Write out the new group file entry.
- X */
- X
- X if (! gr_update (&grp)) {
- X fprintf (stderr, "%s: error adding new group entry\n", Prog);
- X exit (1);
- X }
- X#ifdef NDBM
- X
- X /*
- X * Update the DBM group file with the new entry as well.
- X */
- X
- X if (! gr_dbm_update (&grp)) {
- X fprintf (stderr, "%s: cannot add new dbm group entry\n", Prog);
- X exit (1);
- X }
- X endgrent ();
- X#endif /* NDBM */
- X
- X#ifdef SHADOWGRP
- X
- X /*
- X * Write out the new shadow group entries as well.
- X */
- X
- X if (! sgr_update (&sgrp)) {
- X fprintf (stderr, "%s: error adding new group entry\n", Prog);
- X exit (1);
- X }
- X#ifdef NDBM
- X
- X /*
- X * Update the DBM group file with the new entry as well.
- X */
- X
- X if (! sgr_dbm_update (&sgrp)) {
- X fprintf (stderr, "%s: cannot add new dbm group entry\n", Prog);
- X exit (1);
- X }
- X endsgent ();
- X#endif /* NDBM */
- X#endif /* SHADOWGRP */
- X#ifdef USE_SYSLOG
- X syslog (LOG_INFO, "new group: name=%s, gid=%d\n",
- X group_name, group_id);
- X#endif /* USE_SYSLOG */
- X}
- X
- X/*
- X * find_new_gid - find the next available GID
- X *
- X * find_new_gid() locates the next highest unused GID in the group
- X * file, or checks the given group ID against the existing ones for
- X * uniqueness.
- X */
- X
- Xvoid
- Xfind_new_gid ()
- X{
- X struct group *grp;
- X
- X /*
- X * Start with some GID value if the user didn't provide us with
- X * one already.
- X */
- X
- X if (! gflg)
- X group_id = 100;
- X
- X /*
- X * Search the entire group file, either looking for this
- X * GID (if the user specified one with -g) or looking for the
- X * largest unused value.
- X */
- X
- X for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
- X if (strcmp (group_name, grp->gr_name) == 0) {
- X fprintf (stderr, "%s: name %s is not unique\n",
- X Prog, group_name);
- X exit (1);
- X }
- X if (gflg && group_id == grp->gr_gid) {
- X fprintf (stderr, "%s: gid %d is not unique\n",
- X Prog, group_id);
- X exit (1);
- X }
- X if (! gflg && grp->gr_gid >= group_id)
- X group_id = grp->gr_gid + 1;
- X }
- X}
- X
- X/*
- X * process_flags - perform command line argument setting
- X *
- X * process_flags() interprets the command line arguments and sets
- X * the values that the user will be created with accordingly. The
- X * values are checked for sanity.
- X */
- X
- Xvoid
- Xprocess_flags (argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X extern int optind;
- X extern char *optarg;
- X char *end;
- X int arg;
- X
- X while ((arg = getopt (argc, argv, "og:")) != EOF) {
- X switch (arg) {
- X case 'g':
- X gflg++;
- X if (! isdigit (optarg[0]))
- X usage ();
- X
- X group_id = strtol (optarg, &end, 10);
- X if (*end != '\0') {
- X fprintf (stderr, "%s: invalid group %s\n",
- X Prog, optarg);
- X exit (3);
- X }
- X break;
- X case 'o':
- X if (! gflg)
- X usage ();
- X
- X oflg++;
- X break;
- X default:
- X usage ();
- X }
- X }
- X if (! gflg)
- X find_new_gid ();
- X
- X if (optind == argc - 1)
- X strcpy (group_name, argv[argc - 1]);
- X else
- X usage ();
- X}
- X
- X/*
- X * close_files - close all of the files that were opened
- X *
- X * close_files() closes all of the files that were opened for this
- X * new group. This causes any modified entries to be written out.
- X */
- X
- Xclose_files ()
- X{
- X if (! gr_close ()) {
- X fprintf (stderr, "%s: cannot rewrite group file\n", Prog);
- X exit (1);
- X }
- X (void) gr_unlock ();
- X#ifdef SHADOWGRP
- X if (! sgr_close ()) {
- X fprintf (stderr, "%s: cannot rewrite shadow group file\n",
- X Prog);
- X exit (1);
- X }
- X (void) sgr_unlock ();
- X#endif /* SHADOWGRP */
- X}
- X
- X/*
- X * open_files - lock and open the group files
- X *
- X * open_files() opens the two group files.
- X */
- X
- Xopen_files ()
- X{
- X if (! gr_lock ()) {
- X fprintf (stderr, "%s: unable to lock group file\n", Prog);
- X exit (1);
- X }
- X if (! gr_open (O_RDWR)) {
- X fprintf (stderr, "%s: unable to open group file\n", Prog);
- X exit (1);
- X }
- X#ifdef SHADOWGRP
- X if (! sgr_lock ()) {
- X fprintf (stderr, "%s: unable to lock shadow group file\n",
- X Prog);
- X exit (1);
- X }
- X if (! sgr_open (O_RDWR)) {
- X fprintf (stderr, "%s: unable to open shadow group file\n",
- X Prog);
- X exit (1);
- X }
- X#endif /* SHADOWGRP */
- X}
- X
- X/*
- X * main - useradd command
- X */
- X
- Xmain (argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X
- X /*
- X * Get my name so that I can use it to report errors.
- X */
- X
- X if (Prog = strrchr (argv[0], '/'))
- X Prog++;
- X else
- X Prog = argv[0];
- X
- X#ifdef USE_SYSLOG
- X openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
- X#endif /* USE_SYSLOG */
- X
- X /*
- X * The open routines for the DBM files don't use read-write
- X * as the mode, so we have to clue them in.
- X */
- X
- X#ifdef NDBM
- X gr_dbm_mode = O_RDWR;
- X#ifdef SHADOWGRP
- X sg_dbm_mode = O_RDWR;
- X#endif /* SHADOWGRP */
- X#endif /* NDBM */
- X process_flags (argc, argv);
- X
- X /*
- X * Start with a quick check to see if the group exists.
- X */
- X
- X if (getgrnam (group_name)) {
- X fprintf (stderr, "%s: group %s exists\n", Prog, group_name);
- X exit (9);
- X }
- X
- X /*
- X * Do the hard stuff - open the files, create the group entries,
- X * then close and update the files.
- X */
- X
- X open_files ();
- X
- X grp_update ();
- X
- X close_files ();
- X exit (0);
- X /*NOTREACHED*/
- X}
- END_OF_FILE
- if test 7395 -ne `wc -c <'groupadd.c'`; then
- echo shar: \"'groupadd.c'\" unpacked with wrong size!
- fi
- # end of 'groupadd.c'
- fi
- if test -f 'passwd.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'passwd.c'\"
- else
- echo shar: Extracting \"'passwd.c'\" \(18487 characters\)
- sed "s/^X//" >'passwd.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1989, 1990, 1991, John F. Haugh II
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X */
- X
- X#include <sys/types.h>
- X#include <time.h>
- X#include <stdio.h>
- X#include <fcntl.h>
- X#include <signal.h>
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)passwd.c 3.6 08:43:55 9/12/91";
- X#endif
- X
- X/*
- X * Set up some BSD defines so that all the BSD ifdef's are
- X * kept right here
- X */
- X
- X#ifndef BSD
- X#include <string.h>
- X#include <memory.h>
- X#define bzero(a,n) memset(a, 0, n)
- X#else
- X#include <strings.h>
- X#define strchr index
- X#define strrchr rindex
- X#endif
- X
- X#include "config.h"
- X#include "pwd.h"
- X#include "lastlog.h"
- X#include "shadow.h"
- X
- X#ifdef USE_SYSLOG
- X#include <syslog.h>
- X
- X#ifndef LOG_WARN
- X#define LOG_WARN LOG_WARNING
- X#endif
- X#endif
- X
- X/*
- X * Password aging constants
- X *
- X * DAY - seconds in a day
- X * WEEK - seconds in a week
- X * SCALE - convert from clock to aging units
- X */
- X
- X#define DAY (24L*3600L)
- X#define WEEK (7L*DAY)
- X
- X#ifdef ITI_AGING
- X#define SCALE (1)
- X#else
- X#define SCALE DAY
- X#endif
- X
- X/*
- X * Global variables
- X */
- X
- Xchar name[32]; /* The user's name */
- Xchar *Prog; /* Program name */
- Xint amroot; /* The real UID was 0 */
- X
- X/*
- X * External identifiers
- X */
- X
- Xextern char *getpass();
- Xextern char *pw_encrypt();
- Xextern char *getlogin();
- Xextern int optind; /* Index into argv[] for current option */
- Xextern char *optarg; /* Pointer to current option value */
- X#ifdef NDBM
- Xextern int sp_dbm_mode;
- Xextern int pw_dbm_mode;
- X#endif
- X
- X/*
- X * #defines for messages. This facilities foreign language conversion
- X * since all messages are defined right here.
- X */
- X
- X#define USAGE "usage: %s [ -f | -s ] [ name ]\n"
- X#define ADMUSAGE \
- X " %s [ -x max ] [ -n min ] [ -w warn ] [ -i inact ] name\n"
- X#define ADMUSAGE2 \
- X " %s { -l | -d | -S } name\n"
- X#define OLDPASS "Old Password:"
- X#define NEWPASSMSG \
- X"Enter the new password (minimum of 5 characters)\n\
- XPlease use a combination of upper and lower case letters and numbers.\n"
- X#define CHANGING "Changing password for %s\n"
- X#define NEWPASS "New Password:"
- X#define NEWPASS2 "Re-enter new password:"
- X#define WRONGPWD "Incorrect password for %s.\n"
- X#define WRONGPWD2 "incorrect password for `%s'\n"
- X#define NOMATCH "They don't match; try again.\n"
- X#define CANTCHANGE "The password for %s cannot be changed.\n"
- X#define CANTCHANGE2 "password locked for `%s'\n"
- X#define TOOSOON "Sorry, the password for %s cannot be changed yet.\n"
- X#define TOOSOON2 "now < sp_min for `%s'\n"
- X#define EXECFAILED "%s: Cannot execute %s"
- X#define EXECFAILED2 "cannot execute %s\n"
- X#define WHOAREYOU "%s: Cannot determine you user name.\n"
- X#define UNKUSER "%s: Unknown user %s\n"
- X#define NOPERM "You may not change the password for %s.\n"
- X#define NOPERM2 "can't change pwd for `%s'\n"
- X#define UNCHANGED "The password for %s is unchanged.\n"
- X#define SPWDBUSY "Cannot lock the password file; try again later.\n"
- X#define SPWDBUSY2 "can't lock /etc/shadow\n"
- X#define OPNERROR "Cannot open the password file.\n"
- X#define OPNERROR2 "can't open /etc/shadow\n"
- X#define UPDERROR "Error updating the password entry.\n"
- X#define UPDERROR2 "error updating shadow entry\n"
- X#define DBMERROR "Error updating the DBM password entry.\n"
- X#define DBMERROR2 "error updating DBM shadow entry.\n"
- X#define NOTROOT "Cannot change ID to root.\n"
- X#define NOTROOT2 "can't setuid(0).\n"
- X#define CLSERROR "Cannot commit shadow file changes.\n"
- X#define CLSERROR2 "can't rewrite /etc/shadow.\n"
- X#define UNLKERROR "Cannot unlock the shadow file.\n"
- X#define UNLKERROR2 "can't unlock /etc/shadow.\n"
- X#define TRYAGAIN "Try again.\n"
- X#define CHGPASSWD "changed password for `%s'\n"
- X
- X/*
- X * usage - print command usage and exit
- X */
- X
- Xvoid
- Xusage ()
- X{
- X fprintf (stderr, USAGE, Prog);
- X if (amroot) {
- X fprintf (stderr, ADMUSAGE, Prog);
- X fprintf (stderr, ADMUSAGE2, Prog);
- X }
- X exit (1);
- X}
- X
- X/*
- X * new_password - validate old password and replace with new
- X */
- X
- X/*ARGSUSED*/
- Xint
- Xnew_password (pw, sp)
- Xstruct passwd *pw;
- Xstruct spwd *sp;
- X{
- X char *clear; /* Pointer to clear text */
- X char *cipher; /* Pointer to cipher text */
- X char *cp; /* Pointer to getpass() response */
- X char orig[BUFSIZ]; /* Original password */
- X char pass[BUFSIZ]; /* New password */
- X int i; /* Counter for retries */
- X
- X /*
- X * Authenticate the user. The user will be prompted for their
- X * own password.
- X */
- X
- X if (! amroot && sp->sp_pwdp[0]) {
- X bzero (orig, sizeof orig);
- X
- X if (! (clear = getpass (OLDPASS)))
- X return -1;
- X
- X cipher = pw_encrypt (clear, sp->sp_pwdp);
- X if (strcmp (cipher, sp->sp_pwdp) != 0) {
- X sleep (1);
- X fprintf (stderr, WRONGPWD, sp->sp_namp);
- X#ifdef USE_SYSLOG
- X syslog (LOG_WARN, WRONGPWD2, sp->sp_namp);
- X#endif
- X return -1;
- X }
- X strcpy (orig, clear);
- X bzero (cipher, strlen (cipher));
- X bzero (clear, strlen (clear));
- X }
- X
- X /*
- X * Get the new password. The user is prompted for the new password
- X * and has three tries to get it right. The password will be tested
- X * for strength, unless it is the root user. This provides an escape
- X * for initial login passwords.
- X */
- X
- X printf (NEWPASSMSG);
- X for (i = 0;i < 3;i++) {
- X if (! (cp = getpass (NEWPASS))) {
- X bzero (orig, sizeof orig);
- X return -1;
- X } else
- X strcpy (pass, cp);
- X
- X if (! amroot && ! obscure (orig, pass)) {
- X printf (TRYAGAIN);
- X continue;
- X }
- X if (! (cp = getpass (NEWPASS2))) {
- X bzero (orig, sizeof orig);
- X return -1;
- X }
- X if (strcmp (cp, pass))
- X fprintf (stderr, NOMATCH);
- X else {
- X bzero (cp, strlen (cp));
- X break;
- X }
- X }
- X bzero (orig, sizeof orig);
- X
- X if (i == 3) {
- X bzero (pass, sizeof pass);
- X return -1;
- X }
- X
- X /*
- X * Encrypt the password. The new password is encrypted and
- X * the shadow password structure updated to reflect the change.
- X */
- X
- X sp->sp_pwdp = pw_encrypt (pass, (char *) 0);
- X sp->sp_lstchg = time ((time_t *) 0) / SCALE;
- X bzero (pass, sizeof pass);
- X
- X return 0;
- X}
- X
- X/*
- X * check_password - test a password to see if it can be changed
- X *
- X * check_password() sees if the invoker has permission to change the
- X * password for the given user.
- X */
- X
- X/*ARGSUSED*/
- Xvoid
- Xcheck_password (pw, sp)
- Xstruct passwd *pw;
- Xstruct spwd *sp;
- X{
- X time_t now = time ((time_t *) 0) / SCALE;
- X
- X /*
- X * Root can change any password any time.
- X */
- X
- X if (amroot)
- X return;
- X
- X /*
- X * Expired accounts cannot be changed ever. Passwords
- X * which are locked may not be changed. Passwords where
- X * min > max may not be changed. Passwords which have
- X * been inactive too long cannot be changed.
- X */
- X
- X if ((sp->sp_expire > 0 && now >= sp->sp_expire) ||
- X (sp->sp_inact >= 0 && sp->sp_max >= 0 &&
- X now >= (sp->sp_lstchg + sp->sp_inact + sp->sp_max)) ||
- X strcmp (sp->sp_pwdp, "!") == 0 ||
- X sp->sp_min > sp->sp_max) {
- X fprintf (stderr, CANTCHANGE, sp->sp_namp);
- X#ifdef USE_SYSLOG
- X syslog (LOG_WARN, CANTCHANGE2, sp->sp_namp);
- X closelog ();
- X#endif
- X exit (1);
- X }
- X
- X /*
- X * Passwords may only be changed after sp_min time is up.
- X */
- X
- X if (sp->sp_min >= 0 && now < (sp->sp_lstchg + sp->sp_min)) {
- X fprintf (stderr, TOOSOON, sp->sp_namp);
- X#ifdef USE_SYSLOG
- X syslog (LOG_WARN, TOOSOON2, sp->sp_namp);
- X closelog ();
- X#endif
- X exit (1);
- X }
- X}
- X
- X/*
- X * pwd_to_spwd - create entries for new spwd structure
- X *
- X * pwd_to_spwd() creates a new (struct spwd) containing the
- X * information in the pointed-to (struct passwd).
- X */
- X
- Xvoid
- Xpwd_to_spwd (pw, sp)
- Xstruct passwd *pw;
- Xstruct spwd *sp;
- X{
- X time_t t;
- X
- X /*
- X * Nice, easy parts first. The name and passwd map directly
- X * from the old password structure to the new one.
- X */
- X
- X sp->sp_namp = strdup (pw->pw_name);
- X sp->sp_pwdp = strdup (pw->pw_passwd);
- X#ifdef ATT_AGE
- X
- X /*
- X * AT&T-style password aging maps the sp_min, sp_max, and
- X * sp_lstchg information from the pw_age field, which appears
- X * after the encrypted password.
- X */
- X
- X if (pw->pw_age[0]) {
- X t = (c64i (pw->pw_age[0]) * WEEK) / SCALE;
- X sp->sp_max = t;
- X
- X if (pw->pw_age[1]) {
- X t = (c64i (pw->pw_age[1]) * WEEK) / SCALE;
- X sp->sp_min = t;
- X } else
- X sp->sp_min = (10000L * DAY) / SCALE;
- X
- X if (pw->pw_age[1] && pw->pw_age[2]) {
- X t = (a64l (pw->pw_age + 2) * WEEK) / SCALE;
- X sp->sp_lstchg = t;
- X } else
- X sp->sp_lstchg = time ((time_t *) 0) / SCALE;
- X } else {
- X sp->sp_min = 0;
- X sp->sp_max = (10000L * DAY) / SCALE;
- X sp->sp_lstchg = time ((time_t *) 0) / SCALE;
- X }
- X#else
- X /*
- X * BSD does not use the pw_age field and has no aging information
- X * anywheres. The default values are used to initialize the
- X * fields which are in the missing pw_age field;
- X */
- X
- X sp->sp_min = 0;
- X sp->sp_max = (10000L * DAY) / SCALE;
- X sp->sp_lstchg = time ((time_t *) 0) / SCALE;
- X#endif
- X
- X /*
- X * These fields have no corresponding information in the password
- X * file. They are set to uninitialized values.
- X */
- X
- X sp->sp_warn = -1;
- X sp->sp_inact = -1;
- X sp->sp_expire = -1;
- X sp->sp_flag = -1;
- X}
- X
- X/*
- X * print_status - print current password status
- X */
- X
- X/*ARGSUSED*/
- Xvoid
- Xprint_status (pw, sp)
- Xstruct passwd *pw;
- Xstruct spwd *sp;
- X{
- X struct tm *tm;
- X time_t last_time;
- X
- X last_time = sp->sp_lstchg * SCALE;
- X tm = gmtime (&last_time);
- X
- X printf ("%s ", sp->sp_namp);
- X printf ("%s ",
- X sp->sp_pwdp[0] ? (sp->sp_pwdp[0] == '!' ? "L":"P"):"NP");
- X printf ("%02.2d/%02.2d/%02.2d ",
- X tm->tm_mon + 1, tm->tm_mday, tm->tm_year % 100);
- X printf ("%d %d %d %d\n",
- X (sp->sp_min * SCALE) / DAY, (sp->sp_max * SCALE) / DAY,
- X (sp->sp_warn * SCALE) / DAY, (sp->sp_inact * SCALE) / DAY);
- X}
- X
- X/*
- X * passwd - change a user's password file information
- X *
- X * This command controls the password file and commands which are
- X * used to modify it.
- X *
- X * The valid options are
- X *
- X * -l lock the named account (*)
- X * -d delete the password for the named account (*)
- X * -x # set sp_max to # days (*)
- X * -n # set sp_min to # days (*)
- X * -w # set sp_warn to # days (*)
- X * -i # set sp_inact to # days (*)
- X * -S show password status of named account (*)
- X * -g execute gpasswd command to interpret flags
- X * -f execute chfn command to interpret flags
- X * -s execute chsh command to interpret flags
- X *
- X * (*) requires root permission to execute.
- X *
- X * All of the time fields are entered in days and converted to the
- X * appropriate internal format. For finer resolute the chage
- X * command must be used.
- X */
- X
- Xint
- Xmain (argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X char buf[BUFSIZ]; /* I/O buffer for messages, etc. */
- X char *cp; /* Miscellaneous character pointing */
- X time_t min; /* Minimum days before change */
- X time_t max; /* Maximum days until change */
- X time_t warn; /* Warning days before change */
- X time_t inact; /* Days without change before locked */
- X int i; /* Loop control variable */
- X int flag; /* Current option to process */
- X int lflg = 0; /* -l - lock account option */
- X int dflg = 0; /* -d - delete password option */
- X int xflg = 0; /* -x - set maximum days */
- X int nflg = 0; /* -n - set minimum days */
- X int wflg = 0; /* -w - set warning days */
- X int iflg = 0; /* -i - set inactive days */
- X int Sflg = 0; /* -S - show password status */
- X struct passwd *pw; /* Password file entry for user */
- X struct spwd *sp; /* Shadow file entry for user */
- X struct spwd tspwd; /* New shadow file entry if none */
- X
- X /*
- X * The program behaves differently when executed by root
- X * than when executed by a normal user.
- X */
- X
- X amroot = getuid () == 0;
- X#ifdef NDBM
- X sp_dbm_mode = O_RDWR;
- X pw_dbm_mode = O_RDWR;
- X#endif
- X
- X /*
- X * Get the program name. The program name is used as a
- X * prefix to most error messages. It is also used as input
- X * to the openlog() function for error logging.
- X */
- X
- X if (Prog = strrchr (argv[0], '/'))
- X Prog++;
- X else
- X Prog = argv[0];
- X
- X#ifdef USE_SYSLOG
- X openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
- X#endif
- X
- X /*
- X * Start with the flags which cause another command to be
- X * executed. The effective UID will be set back to the
- X * real UID and the new command executed with the flags
- X */
- X
- X if (argc > 1 && argv[1][0] == '-' && strchr ("gfs", argv[1][1])) {
- X setuid (getuid ());
- X switch (argv[1][1]) {
- X case 'g':
- X argv[1] = "gpasswd";
- X execv ("/bin/gpasswd", &argv[1]);
- X break;
- X case 'f':
- X argv[1] = "chfn";
- X execv ("/bin/chfn", &argv[1]);
- X break;
- X case 's':
- X argv[1] = "chsh";
- X execv ("/bin/chsh", &argv[1]);
- X break;
- X default:
- X usage ();
- X }
- X sprintf (buf, EXECFAILED, Prog, argv[1]);
- X perror (buf);
- X#ifdef USE_SYSLOG
- X syslog (LOG_CRIT, EXECFAILED2, argv[1]);
- X closelog ();
- X#endif
- X exit (1);
- X }
- X
- X /*
- X * The remaining arguments will be processed one by one and
- X * executed by this command. The name is the last argument
- X * if it does not begin with a "-", otherwise the name is
- X * determined from the environment and must agree with the
- X * real UID. Also, the UID will be checked for any commands
- X * which are restricted to root only.
- X */
- X
- X while ((flag = getopt (argc, argv, "ldx:n:w:i:S")) != EOF) {
- X switch (flag) {
- X case 'x':
- X max = strtol (optarg, &cp, 10);
- X if (*cp || getuid ())
- X usage ();
- X
- X xflg++;
- X break;
- X case 'n':
- X min = strtol (optarg, &cp, 10);
- X if (*cp || getuid ())
- X usage ();
- X
- X nflg++;
- X break;
- X case 'w':
- X warn = strtol (optarg, &cp, 10);
- X if (*cp || getuid ())
- X usage ();
- X
- X wflg++;
- X break;
- X case 'i':
- X inact = strtol (optarg, &cp, 10);
- X if (*cp || getuid ())
- X usage ();
- X
- X iflg++;
- X break;
- X case 'S':
- X if (getuid ())
- X usage ();
- X
- X Sflg++;
- X break;
- X case 'd':
- X dflg++;
- X break;
- X case 'l':
- X lflg++;
- X break;
- X default:
- X usage ();
- X }
- X }
- X
- X /*
- X * If any of the flags were given, a user name must be supplied
- X * on the command line. Only an unadorned command line doesn't
- X * require the user's name be given. Also, on -x, -n, -m, and
- X * -i may appear with each other. -d, -l and -S must appear alone.
- X */
- X
- X if ((dflg || lflg || xflg || nflg ||
- X wflg || iflg || Sflg) && optind >= argc)
- X usage ();
- X
- X if ((dflg + lflg + (xflg || nflg || wflg || iflg) + Sflg) > 1)
- X usage ();
- X
- X /*
- X * Now I have to get the user name. The name will be gotten
- X * from the command line if possible. Otherwise it is figured
- X * out from the environment.
- X */
- X
- X if (optind < argc) {
- X strncpy (name, argv[optind], sizeof name);
- X name[sizeof name - 1] = '\0';
- X } else if (amroot) {
- X strcpy (name, "root");
- X } else if (cp = getlogin ()) {
- X strncpy (name, cp, sizeof name);
- X name[sizeof name - 1] = '\0';
- X } else {
- X fprintf (stderr, WHOAREYOU, Prog);
- X#ifdef USE_SYSLOG
- X closelog ();
- X#endif
- X exit (1);
- X }
- X
- X /*
- X * Now I have a name, let's see if the UID for the name
- X * matches the current real UID.
- X */
- X
- X if (! (pw = getpwnam (name))) {
- X fprintf (stderr, UNKUSER, Prog, name);
- X#ifdef USE_SYSLOG
- X closelog ();
- X#endif
- X exit (1);
- X }
- X if (! amroot && pw->pw_uid != getuid ()) {
- X fprintf (stderr, NOPERM, name);
- X#ifdef USE_SYSLOG
- X syslog (LOG_WARN, NOPERM2, name);
- X closelog ();
- X#endif
- X exit (1);
- X }
- X
- X /*
- X * Let the user know whose password is being changed.
- X */
- X
- X if (! Sflg)
- X printf (CHANGING, name);
- X
- X /*
- X * The user name is valid, so let's get the shadow file
- X * entry.
- X */
- X
- X if (! (sp = getspnam (name)))
- X pwd_to_spwd (pw, sp = &tspwd);
- X
- X /*
- X * Save the shadow entry off to the side so it doesn't
- X * get changed by any of the following code.
- X */
- X
- X if (sp != &tspwd) {
- X tspwd = *sp;
- X sp = &tspwd;
- X }
- X tspwd.sp_namp = strdup (sp->sp_namp);
- X tspwd.sp_pwdp = strdup (sp->sp_pwdp);
- X
- X if (Sflg) {
- X print_status (pw, sp);
- X#ifdef USE_SYSLOG
- X closelog ();
- X#endif
- X exit (0);
- X }
- X
- X /*
- X * If there are no other flags, just change the password.
- X */
- X
- X if (! (dflg || lflg || xflg || nflg || wflg || iflg)) {
- X
- X /*
- X * See if the user is permitted to change the password.
- X * Otherwise, go ahead and set a new password.
- X */
- X
- X check_password (pw, sp);
- X
- X if (new_password (pw, sp)) {
- X fprintf (stderr, UNCHANGED, name);
- X#ifdef USE_SYSLOG
- X closelog ();
- X#endif
- X exit (1);
- X }
- X }
- X
- X /*
- X * The other options are incredibly simple. Just modify the
- X * field in the shadow file entry.
- X */
- X
- X if (dflg) /* Set password to blank */
- X sp->sp_pwdp = "";
- X
- X if (lflg) /* Set password to "locked" value */
- X sp->sp_pwdp = "!";
- X
- X if (xflg)
- X sp->sp_max = (max * DAY) / SCALE;
- X
- X if (nflg)
- X sp->sp_min = (min * DAY) / SCALE;
- X
- X if (wflg)
- X sp->sp_warn = (warn * DAY) / SCALE;
- X
- X if (iflg)
- X sp->sp_inact = (inact * DAY) / SCALE;
- X
- X /*
- X * Before going any further, raise the ulimit to prevent
- X * colliding into a lowered ulimit, and set the real UID
- X * to root to protect against unexpected signals. Any
- X * keyboard signals are set to be ignored.
- X */
- X
- X ulimit (2, 30000);
- X if (setuid (0)) {
- X fprintf (stderr, NOTROOT);
- X#ifdef USE_SYSLOG
- X syslog (LOG_ERR, NOTROOT2);
- X closelog ();
- X#endif
- X exit (1);
- X }
- X signal (SIGHUP, SIG_IGN);
- X signal (SIGINT, SIG_IGN);
- X signal (SIGQUIT, SIG_IGN);
- X#ifdef SIGTSTP
- X signal (SIGTSTP, SIG_IGN);
- X#endif
- X
- X /*
- X * The shadow entry is now ready to be committed back to
- X * the shadow file. Get a lock on the file and open it.
- X */
- X
- X for (i = 0;i < 30;i++)
- X if (spw_lock ())
- X break;
- X
- X if (i == 30) {
- X fprintf (stderr, SPWDBUSY);
- X#ifdef USE_SYSLOG
- X syslog (LOG_WARN, SPWDBUSY2);
- X closelog ();
- X#endif
- X exit (1);
- X }
- X if (! spw_open (O_RDWR)) {
- X fprintf (stderr, OPNERROR);
- X#ifdef USE_SYSLOG
- X syslog (LOG_ERR, OPNERROR2);
- X closelog ();
- X#endif
- X (void) spw_unlock ();
- X exit (1);
- X }
- X
- X /*
- X * Update the shadow file entry. If there is a DBM file,
- X * update that entry as well.
- X */
- X
- X if (! spw_update (sp)) {
- X fprintf (stderr, UPDERROR);
- X#ifdef USE_SYSLOG
- X syslog (LOG_ERR, UPDERROR2);
- X closelog ();
- X#endif
- X (void) spw_unlock ();
- X exit (1);
- X }
- X#ifdef NDBM
- X if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_update (sp)) {
- X fprintf (stderr, DBMERROR);
- X#ifdef USE_SYSLOG
- X syslog (LOG_ERR, DBMERROR2);
- X closelog ();
- X#endif
- X (void) spw_unlock ();
- X exit (1);
- X }
- X endspent ();
- X#endif
- X
- X /*
- X * Changes have all been made, so commit them and unlock the
- X * file.
- X */
- X
- X if (! spw_close ()) {
- X fprintf (stderr, CLSERROR);
- X#ifdef USE_SYSLOG
- X syslog (LOG_ERR, CLSERROR2);
- X closelog ();
- X#endif
- X (void) spw_unlock ();
- X exit (1);
- X }
- X if (! spw_unlock ()) {
- X fprintf (stderr, UNLKERROR);
- X#ifdef USE_SYSLOG
- X syslog (LOG_ERR, UNLKERROR2);
- X closelog ();
- X#endif
- X exit (1);
- X }
- X#ifdef USE_SYSLOG
- X syslog (LOG_INFO, CHGPASSWD, name);
- X closelog ();
- X#endif
- X exit (0);
- X /*NOTREACHED*/
- X}
- END_OF_FILE
- if test 18487 -ne `wc -c <'passwd.c'`; then
- echo shar: \"'passwd.c'\" unpacked with wrong size!
- fi
- # end of 'passwd.c'
- fi
- if test -f 'usermod.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'usermod.c'\"
- else
- echo shar: Extracting \"'usermod.c'\" \(24732 characters\)
- sed "s/^X//" >'usermod.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1991, John F. Haugh II
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X */
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)usermod.c 3.5 14:38:40 10/27/91";
- X#endif
- X
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <stdio.h>
- X#include <errno.h>
- X#include "pwd.h"
- X#include <grp.h>
- X#include <ctype.h>
- X#include <fcntl.h>
- X#include <time.h>
- X
- X#ifdef BSD
- X#include <strings.h>
- X#else
- X#include <string.h>
- X#endif
- X
- X#include "config.h"
- X#include "shadow.h"
- X
- X#ifdef USE_SYSLOG
- X#include <syslog.h>
- X
- X#ifndef LOG_WARN
- X#define LOG_WARN LOG_WARNING
- X#endif
- X#endif
- X
- X#ifndef NGROUPS_MAX
- X#define NGROUPS_MAX 64
- X#endif
- X
- X#define VALID(s) (strcspn (s, ":\n") == strlen (s))
- X
- Xchar user_name[BUFSIZ];
- Xchar user_newname[BUFSIZ];
- Xuid_t user_id;
- Xuid_t user_newid;
- Xgid_t user_gid;
- Xchar user_comment[BUFSIZ];
- Xchar user_home[BUFSIZ];
- Xchar user_newhome[BUFSIZ];
- Xchar user_shell[BUFSIZ];
- Xlong user_expire;
- Xlong user_inactive;
- Xint user_ngroups = -1;
- Xgid_t user_groups[NGROUPS_MAX];
- Xstruct passwd user_pwd;
- Xstruct spwd user_spwd;
- X
- Xchar *Prog;
- X
- Xint uflg; /* specify user ID for new account */
- Xint oflg; /* permit non-unique user ID to be specified with -u */
- Xint gflg; /* primary group ID for new account */
- Xint Gflg; /* secondary group set for new account */
- Xint dflg; /* home directory for new account */
- Xint sflg; /* shell program for new account */
- Xint cflg; /* comment (GECOS) field for new account */
- Xint mflg; /* create user's home directory if it doesn't exist */
- Xint fflg; /* days until account with expired password is locked */
- Xint eflg; /* days after password changed before it becomes expired */
- Xint lflg; /* new user name for user */
- X
- X#ifdef NDBM
- Xextern int pw_dbm_mode;
- Xextern int sp_dbm_mode;
- Xextern int gr_dbm_mode;
- X#ifdef SHADOWGRP
- Xextern int sg_dbm_mode;
- X#endif
- X#endif
- Xextern FILE *fopen();
- Xextern int fclose();
- Xextern char *malloc();
- Xextern char *mktemp();
- X
- Xextern struct group *getgrnam();
- Xextern struct group *getgrgid();
- Xextern struct group *gr_next();
- Xextern struct group *gr_locate();
- Xextern int gr_lock();
- Xextern int gr_unlock();
- Xextern int gr_rewind();
- Xextern int gr_open();
- X
- X#ifdef SHADOWGRP
- Xextern struct sgrp *sgr_next();
- Xextern int sgr_lock();
- Xextern int sgr_unlock();
- Xextern int sgr_rewind();
- Xextern int sgr_open();
- X#endif
- X
- Xextern struct passwd *getpwnam();
- Xextern struct passwd *pw_next();
- Xextern struct passwd *pw_locate();
- Xextern int pw_lock();
- Xextern int pw_unlock();
- Xextern int pw_rewind();
- Xextern int pw_open();
- X
- Xextern int spw_lock();
- Xextern int spw_unlock();
- Xextern int spw_open();
- Xextern struct spwd *spw_locate();
- X
- X#define DAY (24L*3600L)
- X#define WEEK (7*DAY)
- X
- X#ifdef ITI_AGING
- X#define SCALE (1)
- X#else
- X#define SCALE (DAY)
- X#endif
- X
- X/*
- X * days and juldays are used to compute the number of days in the
- X * current month, and the cummulative number of days in the preceding
- X * months. they are declared so that january is 1, not 0.
- X */
- X
- Xstatic short days[13] = { 0,
- X 31, 28, 31, 30, 31, 30, /* JAN - JUN */
- X 31, 31, 30, 31, 30, 31 }; /* JUL - DEC */
- X
- Xstatic short juldays[13] = { 0,
- X 0, 31, 59, 90, 120, 151, /* JAN - JUN */
- X 181, 212, 243, 273, 304, 334 }; /* JUL - DEC */
- X
- X#ifdef NEED_RENAME
- X/*
- X * rename - rename a file to another name
- X *
- X * rename is provided for systems which do not include the rename()
- X * system call.
- X */
- X
- Xint
- Xrename (begin, end)
- Xchar *begin;
- Xchar *end;
- X{
- X struct stat s1, s2;
- X extern int errno;
- X int orig_err = errno;
- X
- X if (stat (begin, &s1))
- X return -1;
- X
- X if (stat (end, &s2)) {
- X errno = orig_err;
- X } else {
- X
- X /*
- X * See if this is a cross-device link. We do this to
- X * insure that the link below has a chance of working.
- X */
- X
- X if (s1.st_dev != s2.st_dev) {
- X errno = EXDEV;
- X return -1;
- X }
- X
- X /*
- X * See if we can unlink the existing destination
- X * file. If the unlink works the directory is writable,
- X * so there is no need here to figure that out.
- X */
- X
- X if (unlink (end))
- X return -1;
- X }
- X
- X /*
- X * Now just link the original name to the final name. If there
- X * was no file previously, this link will fail if the target
- X * directory isn't writable. The unlink will fail if the source
- X * directory isn't writable, but life stinks ...
- X */
- X
- X if (link (begin, end) || unlink (begin))
- X return -1;
- X
- X return 0;
- X}
- X#endif
- X
- X/*
- X * strtoday - compute the number of days since 1970.
- X *
- X * the total number of days prior to the current date is
- X * computed. january 1, 1970 is used as the origin with
- X * it having a day number of 0.
- X */
- X
- Xlong
- Xstrtoday (str)
- Xchar *str;
- X{
- X char slop[2];
- X int month;
- X int day;
- X int year;
- X long total;
- X
- X /*
- X * start by separating the month, day and year. this is
- X * a chauvanistic program - it only takes date input in
- X * the standard USA format.
- X */
- X
- X if (sscanf (str, "%d/%d/%d%c", &month, &day, &year, slop) != 3)
- X return -1;
- X
- X /*
- X * the month, day of the month, and year are checked for
- X * correctness and the year adjusted so it falls between
- X * 1970 and 2069.
- X */
- X
- X if (month < 1 || month > 12)
- X return -1;
- X
- X if (day < 1)
- X return -1;
- X
- X if ((month != 2 || (year % 4) != 0) && day > days[month])
- X return -1;
- X else if ((month == 2 && (year % 4) == 0) && day > 29)
- X return -1;
- X
- X if (year < 0)
- X return -1;
- X else if (year < 69)
- X year += 2000;
- X else if (year < 99)
- X year += 1900;
- X
- X if (year < 1970 || year > 2069)
- X return -1;
- X
- X /*
- X * the total number of days is the total number of days in all
- X * the whole years, plus the number of leap days, plus the
- X * number of days in the whole months preceding, plus the number
- X * of days so far in the month.
- X */
- X
- X total = (long) ((year - 1970) * 365L) + (((year + 1) - 1970) / 4);
- X total += (long) juldays[month] + (month > 2 && (year % 4) == 0 ? 1:0);
- X total += (long) day - 1;
- X
- X return total;
- X}
- X
- X/*
- X * add_list - add a member to a list of group members
- X *
- X * the array of member names is searched for the new member
- X * name, and if not present it is added to a freshly allocated
- X * list of users.
- X */
- X
- Xchar **
- Xadd_list (list, member)
- Xchar **list;
- Xchar *member;
- X{
- X int i;
- X char **tmp;
- X
- X /*
- X * Scan the list for the new name. Return the original list
- X * pointer if it is present.
- X */
- X
- X for (i = 0;list[i] != (char *) 0;i++)
- X if (strcmp (list[i], member) == 0)
- X return list;
- X
- X /*
- X * Allocate a new list pointer large enough to hold all the
- X * old entries, and the new entries as well.
- X */
- X
- X if (! (tmp = (char **) malloc ((i + 2) * sizeof member)))
- X return 0;
- X
- X /*
- X * Copy the original list to the new list, then append the
- X * new member and NULL terminate the result. This new list
- X * is returned to the invoker.
- X */
- X
- X for (i = 0;list[i] != (char *) 0;i++)
- X tmp[i] = list[i];
- X
- X tmp[i++] = strdup (member);
- X tmp[i] = (char *) 0;
- X
- X return tmp;
- X}
- X
- X/*
- X * del_list - delete a member from a list of group members
- X *
- X * the array of member names is searched for the old member
- X * name, and if present it is deleted from a freshly allocated
- X * list of users.
- X */
- X
- Xchar **
- Xdel_list (list, member)
- Xchar **list;
- Xchar *member;
- X{
- X int i, j;
- X char **tmp;
- X
- X /*
- X * Scan the list for the new name. Return the original list
- X * pointer if it is present.
- X */
- X
- X for (i = j = 0;list[i] != (char *) 0;i++)
- X if (strcmp (list[i], member))
- X j++;
- X
- X if (j == i)
- X return list;
- X
- X /*
- X * Allocate a new list pointer large enough to hold all the
- X * old entries, and the new entries as well.
- X */
- X
- X if (! (tmp = (char **) malloc ((j + 2) * sizeof member)))
- X return 0;
- X
- X /*
- X * Copy the original list to the new list, then append the
- X * new member and NULL terminate the result. This new list
- X * is returned to the invoker.
- X */
- X
- X for (i = j = 0;list[i] != (char *) 0;i++)
- X if (strcmp (list[i], member))
- X tmp[j++] = list[i];
- X
- X tmp[j] = (char *) 0;
- X
- X return tmp;
- X}
- X
- X/*
- X * get_groups - convert a list of group names to an array of group IDs
- X *
- X * get_groups() takes a comma-separated list of group names and
- X * converts it to an array of group ID values. Any unknown group
- X * names are reported as errors.
- X */
- X
- Xint
- Xget_groups (list)
- Xchar *list;
- X{
- X char *cp;
- X struct group *grp;
- X int errors = 0;
- X
- X /*
- X * Initialize the list to be empty
- X */
- X
- X user_ngroups = 0;
- X
- X if (! *list)
- X return 0;
- X
- X /*
- X * So long as there is some data to be converted, strip off
- X * each name and look it up. A mix of numerical and string
- X * values for group identifiers is permitted.
- X */
- X
- X do {
- X /*
- X * Strip off a single name from the list
- X */
- X
- X if (cp = strchr (list, ','))
- X *cp++ = '\0';
- X
- X /*
- X * Names starting with digits are treated as numerical
- X * GID values, otherwise the string is looked up as is.
- X */
- X
- X if (isdigit (*list))
- X grp = getgrgid (atoi (list));
- X else
- X grp = getgrnam (list);
- X
- X /*
- X * There must be a match, either by GID value or by
- X * string name.
- X */
- X
- X if (! grp) {
- X fprintf (stderr, "%s: unknown group %s\n", Prog, list);
- X errors++;
- X }
- X
- X /*
- X * Add the GID value from the group file to the user's
- X * list of groups.
- X */
- X
- X user_groups[user_ngroups++] = grp->gr_gid;
- X
- X list = cp;
- X } while (list);
- X
- X /*
- X * Any errors in finding group names are fatal
- X */
- X
- X if (errors)
- X return -1;
- X
- X return 0;
- X}
- X
- X/*
- X * usage - display usage message and exit
- X */
- X
- Xusage ()
- X{
- X fprintf (stderr,
- X "usage: %s [-u uid [-o]] [-g group] [-G group,...] \n", Prog);
- X fprintf (stderr,
- X "\t\t[-d home [-m]] [-s shell] [-c comment] [-l new_name]\n");
- X fprintf (stderr,
- X "\t\t[-f inactive] [-e expire] name\n");
- X
- X exit (2);
- X}
- X
- X/*
- X * new_pwent - initialize the values in a password file entry
- X *
- X * new_pwent() takes all of the values that have been entered and
- X * fills in a (struct passwd) with them.
- X */
- X
- Xvoid
- Xnew_pwent (pwent)
- Xstruct passwd *pwent;
- X{
- X if (lflg)
- X pwent->pw_name = strdup (user_newname);
- X
- X if (uflg)
- X pwent->pw_uid = user_newid;
- X
- X if (gflg)
- X pwent->pw_gid = user_gid;
- X
- X if (cflg)
- X pwent->pw_gecos = strdup (user_comment);
- X
- X if (dflg)
- X pwent->pw_dir = strdup (user_newhome);
- X
- X if (sflg)
- X pwent->pw_shell = strdup (user_shell);
- X}
- X
- X/*
- X * new_spent - initialize the values in a shadow password file entry
- X *
- X * new_spent() takes all of the values that have been entered and
- X * fills in a (struct spwd) with them.
- X */
- X
- Xvoid
- Xnew_spent (spent)
- Xstruct spwd *spent;
- X{
- X if (lflg)
- X spent->sp_namp = strdup (user_newname);
- X
- X spent->sp_inact = user_inactive;
- X spent->sp_expire = user_expire;
- X}
- X
- X/*
- X * grp_update - add user to secondary group set
- X *
- X * grp_update() takes the secondary group set given in user_groups
- X * and adds the user to each group given by that set.
- X */
- X
- Xvoid
- Xgrp_update ()
- X{
- X int i;
- X int is_member;
- X int was_member;
- X int was_admin;
- X struct group *grp;
- X struct sgrp *sgrp;
- X
- X /*
- X * Lock and open the group file. This will load all of the group
- X * entries.
- X */
- X
- X if (! gr_lock ()) {
- X fprintf (stderr, "%s: error locking group file\n", Prog);
- X exit (1);
- X }
- X if (! gr_open (O_RDWR)) {
- X fprintf (stderr, "%s: error opening group file\n", Prog);
- X exit (1);
- X }
- X#ifdef SHADOWGRP
- X if (! sgr_lock ()) {
- X fprintf (stderr, "%s: error locking shadow group file\n", Prog);
- X exit (1);
- X }
- X if (! sgr_open (O_RDWR)) {
- X fprintf (stderr, "%s: error opening shadow group file\n", Prog);
- X exit (1);
- X }
- X#endif
- X
- X /*
- X * Scan through the entire group file looking for the groups that
- X * the user is a member of.
- X */
- X
- X for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
- X
- X /*
- X * See if the user specified this group as one of their
- X * concurrent groups.
- X */
- X
- X for (i = 0;i < user_ngroups;i++)
- X if (grp->gr_gid == user_groups[i])
- X break;
- X
- X is_member = i == user_ngroups ? -1:i;
- X
- X for (i = 0;grp->gr_mem[i];i++)
- X if (strcmp (user_name, grp->gr_mem[i]) == 0)
- X break;
- X
- X was_member = grp->gr_mem[i] ? i:-1;
- X
- X if (is_member == -1 && was_member == -1)
- X continue;
- X
- X if (was_member >= 0 && (! Gflg || is_member >= 0)) {
- X if (lflg) {
- X grp->gr_mem = del_list (grp->gr_mem,
- X user_name);
- X grp->gr_mem = add_list (grp->gr_mem,
- X user_newname);
- X#ifdef USE_SYSLOG
- X syslog (LOG_INFO,
- X "change `%s' to `%s' in group `%s'\n",
- X user_name, user_newname, grp->gr_name);
- X#endif
- X }
- X } else if (was_member >= 0 && Gflg && is_member < 0) {
- X grp->gr_mem = del_list (grp->gr_mem, user_name);
- X#ifdef USE_SYSLOG
- X syslog (LOG_INFO, "delete `%s' from group `%s'\n",
- X user_name, grp->gr_name);
- X#endif
- X } else if (was_member < 0 && Gflg && is_member >= 0) {
- X grp->gr_mem = add_list (grp->gr_mem,
- X lflg ? user_newname:user_name);
- X#ifdef USE_SYSLOG
- X syslog (LOG_INFO, "add `%s' to group `%s'\n",
- X lflg ? user_newname:user_name, grp->gr_name);
- X#endif
- X } else
- X continue;
- X
- X if (! gr_update (grp)) {
- X fprintf (stderr, "%s: error adding new group entry\n",
- X Prog);
- X exit (1);
- X }
- X#ifdef NDBM
- X /*
- X * Update the DBM group file with the new entry as well.
- X */
- X
- X if (! gr_dbm_update (grp)) {
- X fprintf (stderr, "%s: cannot add new dbm group entry\n",
- X Prog);
- X exit (1);
- X }
- X endgrent ();
- X#endif
- X }
- X
- X#ifdef SHADOWGRP
- X /*
- X * Scan through the entire shadow group file looking for the groups
- X * that the user is a member of.
- X */
- X
- X for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
- X
- X /*
- X * See if the user was a member of this group
- X */
- X
- X for (i = 0;sgrp->sg_mem[i];i++)
- X if (strcmp (sgrp->sg_mem[i], user_name) == 0)
- X break;
- X
- X was_member = sgrp->sg_mem[i] ? i:-1;
- X
- X /*
- X * See if the user was an administrator of this group
- X */
- X
- X for (i = 0;sgrp->sg_adm[i];i++)
- X if (strcmp (sgrp->sg_adm[i], user_name) == 0)
- X break;
- X
- X was_admin = sgrp->sg_adm[i] ? i:-1;
- X
- X /*
- X * See if the user specified this group as one of their
- X * concurrent groups.
- X */
- X
- X for (i = 0;i < user_ngroups;i++) {
- X if (! (grp = gr_locate (sgrp->sg_name)))
- X continue;
- X
- X if (grp->gr_gid == user_groups[i])
- X break;
- X }
- X is_member = i == user_ngroups ? -1:i;
- X
- X if (is_member == -1 && was_admin == -1 && was_member == -1)
- X continue;
- X
- X if (was_admin >= 0 && lflg) {
- X sgrp->sg_adm = del_list (sgrp->sg_adm, user_name);
- X sgrp->sg_adm = add_list (sgrp->sg_adm, user_newname);
- X#ifdef USE_SYSLOG
- X syslog (LOG_INFO, "change admin `%s' to `%s' in shadow group `%s'\n",
- X user_name, user_newname, sgrp->sg_name);
- X#endif
- X }
- X if (was_member >= 0 && (! Gflg || is_member >= 0)) {
- X if (lflg) {
- X sgrp->sg_mem = del_list (sgrp->sg_mem,
- X user_name);
- X sgrp->sg_mem = add_list (sgrp->sg_mem,
- X user_newname);
- X#ifdef USE_SYSLOG
- X syslog (LOG_INFO, "change `%s' to `%s' in shadow group `%s'\n",
- X user_name, user_newname, sgrp->sg_name);
- X#endif
- X }
- X } else if (was_member >= 0 && Gflg && is_member < 0) {
- X sgrp->sg_mem = del_list (sgrp->sg_mem, user_name);
- X#ifdef USE_SYSLOG
- X syslog (LOG_INFO, "delete `%s' from shadow group `%s'\n",
- X user_name, sgrp->sg_name);
- X#endif
- X } else if (was_member < 0 && Gflg && is_member >= 0) {
- X sgrp->sg_mem = add_list (sgrp->sg_mem,
- X lflg ? user_newname:user_name);
- X#ifdef USE_SYSLOG
- X syslog (LOG_INFO, "add `%s' to shadow group `%s'\n",
- X lflg ? user_newname:user_name, grp->gr_name);
- X#endif
- X } else
- X continue;
- X
- X /*
- X * Update the group entry to reflect the changes.
- X */
- X
- X if (! sgr_update (sgrp)) {
- X fprintf (stderr, "%s: error adding new group entry\n",
- X Prog);
- X exit (1);
- X }
- X#ifdef NDBM
- X /*
- X * Update the DBM group file with the new entry as well.
- X */
- X
- X if (! sgr_dbm_update (sgrp)) {
- X fprintf (stderr, "%s: cannot add new dbm group entry\n",
- X Prog);
- X exit (1);
- X }
- X endsgent ();
- X#endif
- X }
- X#endif
- X}
- X
- X/*
- X * check_new_id - verify the new UID for uniqueness
- X *
- X * check_new_id() insures that the new UID does not exist already.
- X * It does this by checking that the UID has changed and that there
- X * is no current entry for this user ID.
- X */
- X
- Xint
- Xcheck_new_id ()
- X{
- X /*
- X * First, the easy stuff. If the ID can be duplicated, or if
- X * the ID didn't really change, just return. If the ID didn't
- X * change, turn off those flags. No sense doing needless work.
- X */
- X
- X if (oflg)
- X return 0;
- X
- X if (user_id == user_newid) {
- X uflg = lflg = 0;
- X return 0;
- X }
- X if (getpwuid (user_newid))
- X return -1;
- X
- X return 0;
- X}
- X
- X/*
- X * process_flags - perform command line argument setting
- X *
- X * process_flags() interprets the command line arguments and sets
- X * the values that the user will be created with accordingly. The
- X * values are checked for sanity.
- X */
- X
- Xvoid
- Xprocess_flags (argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X extern int optind;
- X extern char *optarg;
- X struct group *grp;
- X struct passwd *pwd;
- X struct spwd *spwd;
- X long l;
- X int anyflag = 0;
- X int arg;
- X
- X if (argc == 1 || argv[argc - 1][0] == '-')
- X usage ();
- X
- X if (! (pwd = getpwnam (argv[argc - 1]))) {
- X fprintf (stderr, "%s: user %s does not exist\n",
- X Prog, argv[argc - 1]);
- X exit (6);
- X }
- X strcpy (user_name, pwd->pw_name);
- X user_id = pwd->pw_uid;
- X user_gid = pwd->pw_gid;
- X strcpy (user_comment, pwd->pw_gecos);
- X strcpy (user_home, pwd->pw_dir);
- X strcpy (user_shell, pwd->pw_shell);
- X
- X if (spwd = getspnam (user_name)) {
- X user_expire = spwd->sp_expire;
- X user_inactive = spwd->sp_inact;
- X }
- X while ((arg = getopt (argc, argv, "u:og:G:d:s:c:mf:e:l:")) != EOF) {
- X switch (arg) {
- X case 'c':
- X if (! VALID (optarg)) {
- X fprintf (stderr,
- X "%s: invalid field `%s'\n",
- X Prog, optarg);
- X exit (3);
- X }
- X if (strcmp (optarg, user_comment)) {
- X cflg++;
- X strncpy (user_comment, optarg, BUFSIZ);
- X }
- X break;
- X case 'd':
- X if (! VALID (optarg)) {
- X fprintf (stderr,
- X "%s: invalid field `%s'\n",
- X Prog, optarg);
- X exit (3);
- X }
- X dflg++;
- X strncpy (user_newhome, optarg, BUFSIZ);
- X break;
- X case 'e':
- X l = strtoday (optarg);
- X#ifdef ITI_AGING
- X l *= DAY;
- X#endif
- X if (l != user_expire) {
- X eflg++;
- X user_expire = l;
- X }
- X break;
- X case 'f':
- X if (user_inactive != atoi (optarg)) {
- X fflg++;
- X user_inactive = atoi (optarg);
- X }
- X break;
- X case 'g':
- X if (isdigit (optarg[0]))
- X grp = getgrgid (atoi (optarg));
- X else
- X grp = getgrnam (optarg);
- X
- X if (! grp) {
- X fprintf (stderr,
- X "%s: unknown group %s\n",
- X Prog, optarg);
- X exit (1);
- X }
- X if (grp->gr_gid != user_gid) {
- X gflg++;
- X user_gid = grp->gr_gid;
- X }
- X break;
- X case 'G':
- X Gflg++;
- X if (get_groups (optarg))
- X exit (1);
- X
- X break;
- X case 'l':
- X if (! VALID (optarg)) {
- X fprintf (stderr,
- X "%s: invalid field `%s'\n",
- X Prog, optarg);
- X exit (3);
- X }
- X if (strcmp (user_name, optarg)) {
- X lflg++;
- X strcpy (user_newname, optarg);
- X }
- X break;
- X case 'm':
- X if (! dflg)
- X usage ();
- X
- X mflg++;
- X break;
- X case 'o':
- X if (! uflg)
- X usage ();
- X
- X oflg++;
- X break;
- X case 's':
- X if (! VALID (optarg)) {
- X fprintf (stderr,
- X "%s: invalid field `%s'\n",
- X Prog, optarg);
- X exit (3);
- X }
- X if (strcmp (user_shell, optarg)) {
- X strncpy (user_shell, optarg, BUFSIZ);
- X sflg++;
- X }
- X break;
- X case 'u':
- X uflg++;
- X user_newid = atoi (optarg);
- X break;
- X default:
- X usage ();
- X }
- X anyflag++;
- X }
- X if (anyflag == 0) {
- X fprintf (stderr, "%s: no flags given\n", Prog);
- X exit (1);
- X }
- X if (optind != argc - 1)
- X usage ();
- X
- X if (dflg && strcmp (user_home, user_newhome) == 0)
- X dflg = mflg = 0;
- X
- X if (uflg && user_id == user_newid)
- X uflg = oflg = 0;
- X
- X if (lflg && getpwnam (user_newname)) {
- X fprintf (stderr, "%s: user %s exists\n", Prog, user_newname);
- X exit (9);
- X }
- X}
- X
- X/*
- X * close_files - close all of the files that were opened
- X *
- X * close_files() closes all of the files that were opened for this
- X * new user. This causes any modified entries to be written out.
- X */
- X
- Xclose_files ()
- X{
- X if (! pw_close ()) {
- X fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
- X exit (1);
- X }
- X if (! spw_close ()) {
- X fprintf (stderr, "%s: cannot rewrite shadow password file\n",
- X Prog);
- X exit (1);
- X }
- X if (user_ngroups >= 0) {
- X if (! gr_close ()) {
- X fprintf (stderr, "%s: cannot rewrite group file\n",
- X Prog);
- X exit (1);
- X }
- X (void) gr_unlock ();
- X#ifdef SHADOWGRP
- X if (! sgr_close ()) {
- X fprintf (stderr, "%s: cannot rewrite shadow group file\n",
- X Prog);
- X exit (1);
- X }
- X (void) sgr_unlock ();
- X#endif
- X }
- X (void) spw_unlock ();
- X (void) pw_unlock ();
- X}
- X
- X/*
- X * open_files - lock and open the password files
- X *
- X * open_files() opens the two password files.
- X */
- X
- Xopen_files ()
- X{
- X if (! pw_lock ()) {
- X fprintf (stderr, "%s: unable to lock password file\n", Prog);
- X exit (1);
- X }
- X if (! pw_open (O_RDWR)) {
- X fprintf (stderr, "%s: unable to open password file\n", Prog);
- X exit (1);
- X }
- X if (! spw_lock ()) {
- X fprintf (stderr, "%s: cannot lock shadow password file\n", Prog);
- X exit (1);
- X }
- X if (! spw_open (O_RDWR)) {
- X fprintf (stderr, "%s: cannot open shadow password file\n", Prog);
- X exit (1);
- X }
- X}
- X
- X/*
- X * usr_update - create the user entries
- X *
- X * usr_update() creates the password file entries for this user
- X * and will update the group entries if required.
- X */
- X
- Xusr_update ()
- X{
- X struct passwd pwent;
- X struct spwd spent;
- X struct passwd *pwd;
- X struct spwd *spwd;
- X
- X pwd = pw_locate (user_name);
- X pwent = *pwd;
- X
- X spwd = spw_locate (user_name);
- X spent = *spwd;
- X
- X new_pwent (&pwent);
- X new_spent (&spent);
- X
- X if (lflg || uflg || gflg || cflg || dflg || sflg) {
- X if (! pw_update (&pwent)) {
- X fprintf (stderr, "%s: error changing password entry\n",
- X Prog);
- X exit (1);
- X }
- X if (lflg && ! pw_remove (user_name)) {
- X fprintf (stderr, "%s: error removing password entry\n",
- X Prog);
- X exit (1);
- X }
- X#if defined(DBM) || defined(NDBM)
- X if (access ("/etc/passwd.pag", 0) == 0) {
- X if (! pw_dbm_update (&pwent)) {
- X fprintf (stderr, "%s: error adding password dbm entry\n",
- X Prog);
- X exit (1);
- X }
- X if (lflg && (pwd = getpwnam (user_name)) && ! pw_dbm_remove (pwd)) {
- X fprintf (stderr, "%s: error removing passwd dbm entry\n",
- X Prog);
- X exit (1);
- X }
- X endpwent ();
- X }
- X#endif
- X }
- X if (lflg || eflg || fflg) {
- X if (! spw_update (&spent)) {
- X fprintf (stderr, "%s: error adding new shadow password entry\n",
- X Prog);
- X exit (1);
- X }
- X if (lflg && ! spw_remove (user_name)) {
- X fprintf (stderr, "%s: error removing shadow password entry\n",
- X Prog);
- X exit (1);
- X }
- X }
- X#ifdef NDBM
- X if (access ("/etc/shadow.pag", 0) == 0) {
- X if (! sp_dbm_update (&spent)) {
- X fprintf (stderr, "%s: error updating shadow passwd dbm entry\n",
- X Prog);
- X exit (1);
- X }
- X if (lflg && ! sp_dbm_remove (user_name)) {
- X fprintf (stderr, "%s: error removing shadow passwd db entry\n",
- X Prog);
- X exit (1);
- X }
- X endspent ();
- X }
- X#endif
- X if (Gflg || lflg)
- X grp_update ();
- X}
- X
- X/*
- X * move_home - move the user's home directory
- X *
- X * move_home() creates the user's home directory if it does not
- X * already exist. It will be created mode 755 owned by the user
- X * with the user's default group.
- X */
- X
- Xmove_home ()
- X{
- X struct stat sb;
- X
- X if (mflg && stat (user_home, &sb) == 0) {
- X if (access (user_newhome, 0) == 0) {
- X fprintf (stderr, "%s: directory %s exists\n",
- X Prog, user_newhome);
- X exit (12);
- X } else if (rename (user_home, user_newhome)) {
- X if (errno == EXDEV) {
- X if (mkdir (user_newhome, sb.st_mode & 0777)) {
- X fprintf (stderr,
- X "%s: can't create %s\n",
- X Prog, user_newhome);
- X }
- X chown (user_newhome, sb.st_uid, sb.st_gid);
- X if (copy_tree (user_home, user_newhome,
- X -1, -1) == 0 &&
- X remove_tree (user_home) == 0 &&
- X rmdir (user_home) == 0)
- X return;
- X
- X remove_tree (user_newhome);
- X rmdir (user_newhome);
- X }
- X fprintf (stderr,
- X "%s: cannot rename directory %s to %s\n",
- X Prog, user_home, user_newhome);
- X exit (12);
- X }
- X }
- X if (uflg || gflg)
- X chown (dflg ? user_newhome:user_home, user_id, user_gid);
- X}
- X
- X/*
- X * main - useradd command
- X */
- X
- Xmain (argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X /*
- X * Get my name so that I can use it to report errors.
- X */
- X
- X if (Prog = strrchr (argv[0], '/'))
- X Prog++;
- X else
- X Prog = argv[0];
- X
- X#ifdef USE_SYSLOG
- X openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
- X#endif
- X
- X /*
- X * The open routines for the DBM files don't use read-write
- X * as the mode, so we have to clue them in.
- X */
- X
- X#if defined(DBM) || defined(NDBM)
- X pw_dbm_mode = O_RDWR;
- X#endif
- X#ifdef NDBM
- X sp_dbm_mode = O_RDWR;
- X gr_dbm_mode = O_RDWR;
- X#ifdef SHADOWGRP
- X sg_dbm_mode = O_RDWR;
- X#endif
- X#endif
- X process_flags (argc, argv);
- X
- X /*
- X * Do the hard stuff - open the files, change the user entries,
- X * change the home directory, then close and update the files.
- X */
- X
- X open_files ();
- X
- X usr_update ();
- X
- X close_files ();
- X
- X if (mflg)
- X move_home ();
- X
- X exit (0);
- X /*NOTREACHED*/
- X}
- END_OF_FILE
- if test 24732 -ne `wc -c <'usermod.c'`; then
- echo shar: \"'usermod.c'\" unpacked with wrong size!
- fi
- # end of 'usermod.c'
- fi
- echo shar: End of archive 2 \(of 11\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 11 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-